﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

using Microsoft.Crm.Sdk;
using Microsoft.Crm.Sdk.Query;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Crm.SdkTypeProxy.Metadata;
using Microsoft.Crm.Sdk.Metadata;

using Custom.Crm.General.Utility;

namespace Custom.Crm.General
{
    public class Concate : IPlugin
    {
        /// <summary>The XML defining the field & concation mappings</summary>
        private XmlDocument m_concateDoc = null;

        private PropertyUtility m_propertyUtil = null;
        private Dictionary<string, string> m_mapCollection = null;

        /// <summary>
        /// Constructor for the class - recieves two variables when the workflow engine.
        /// </summary>
        /// <param name="unSecure">Unsecure data entered while registering the plugin.
        /// Example of unSecure configuration:  (See Concate.xml)
        /// </param>
        /// <param name="Secure">Secure data entered while registering the plugin</param>
        public Concate(string unSecure, string Secure)
        {
            if (unSecure != null && unSecure.Length > 0)
            {
                try
                {
                    // Get the Configurations from the unSecure properties.
                    m_concateDoc = new XmlDocument();
                    m_concateDoc.LoadXml(unSecure);
                }
                catch (XmlException)
                {
                    throw new Exception("Invalid Mapping XML");
                }
            }
        }

        public void Execute(IPluginExecutionContext context)
        {
            if (m_concateDoc != null)
            {
                // Set a reference to the Property Utility under the current context
                m_propertyUtil = new Utility.PropertyUtility(context);

                foreach (XmlNode mapNode in m_concateDoc.DocumentElement.ChildNodes)
                {
                    try
                    {
                        // Get the target field from the XML
                        string targetFieldName = mapNode.Attributes["fieldname"].Value;

                        // Get the rule from the XML
                        string ruleValue = mapNode.SelectSingleNode("rule").InnerText;

                        // Initalise the Map Collection for this mapping
                        m_mapCollection = new Dictionary<string, string>();

                        foreach (XmlNode fieldNode in mapNode.SelectSingleNode("fields").ChildNodes)
                        {
                            // Get map and source field name from XML.
                            string fieldName = fieldNode.Attributes["fieldname"].Value;
                            string mapName = fieldNode.Attributes["mapname"].Value;

                            // Determine whether we need to get the label from the mapped field.
                            bool getLabel = false;
                            if (fieldNode.Attributes["getlabel"] != null && fieldNode.Attributes["getlabel"].Value == "true")
                                getLabel = true;

                            // Set the format of the property's value' ToString parameter
                            string format = null;
                            if (fieldNode.Attributes["format"] != null && fieldNode.Attributes["format"].Value.Length > 0)
                                format = fieldNode.Attributes["format"].Value;

                            // Get the mapped field value from the current object.
                            object property = m_propertyUtil.GetPropertyFromContext(fieldName);
                            string value = m_propertyUtil.GetAttributeValue(property, getLabel, format);

                            // Handle no value being found.
                            if (value == null)
                            {
                                // Check to see if there is a default parameter.
                                if (fieldNode.Attributes["default"] != null && fieldNode.Attributes["default"].Value.Length > 0)
                                    value = fieldNode.Attributes["default"].Value;
                                else
                                    // Set to an empty string so the replace is handled.
                                    value = string.Empty;
                            }

                            // Set the value in the mapped field's collection for processing.
                            m_mapCollection.Add(mapName, value);
                        }

                        // Iterate through the mapped field's key & value and replace the placeholders in the rule.
                        foreach (KeyValuePair<string, string> mapEntry in m_mapCollection)
                        {
                            ruleValue = ruleValue.Replace("#" + mapEntry.Key + "#", mapEntry.Value);
                        }

                        // Set the target field's value to the processed rule value.
                        m_propertyUtil.SetAttributeValueOnTarget(targetFieldName, ruleValue);
                    }
                    catch(Exception ex)
                    {
                        System.Diagnostics.Debug.WriteLine(ex.Message);
                        // IGNORE: Don't stop processing due to exception.
                    }
                }
            }
        }
    }
}
